package com.huayanginfo.saas.directory;

import java.io.IOException;
import java.util.Properties;

import javax.naming.Context;
import javax.naming.NamingEnumeration;
import javax.naming.NamingException;
import javax.naming.directory.Attribute;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.directory.DirContext;
import javax.naming.directory.InitialDirContext;
import javax.naming.directory.SearchControls;
import javax.naming.directory.SearchResult;

import com.huayanginfo.saas.datasource.ConnectionInfo;
import com.huayanginfo.saas.domain.member.User;
import com.huayanginfo.saas.support.Security;

@SuppressWarnings({ "rawtypes" })
public class LDAPService {

	public static final String CONTEXTENTRY = "dc=saas";//"ou=system";
	public static final String DELIMITER = ",";
	
	private static Properties properties = new Properties();
	static {
		try {
			properties.load(LDAPService.class.getResourceAsStream("/ldap.properties"));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	/**
	 * 增加公司到LDAP
	 * 
	 * @param user
	 * @param connectionInfo
	 * @return Company DN
	 * @throws NamingException
	 */
	public static synchronized String addCompany(String companyName, ConnectionInfo connectionInfo)
			throws NamingException {
		InitialDirContext context = new InitialDirContext(properties);
		DirContext subContext = null;
		try {
		Attributes companyAttributes = AttributeFactory.createCompanyAttribute(companyName,
				connectionInfo);
		subContext = context.createSubcontext(
				"o=" + companyName, companyAttributes);
		} finally {
			context.close();
		}
		
		return subContext.getNameInNamespace();
	}
	
	/**
	 * 增加用户到公司下
	 * @param companyRDN
	 * @param user
	 * @throws NamingException
	 */
	public static synchronized void addUser(String companyRDN, User user) throws NamingException {
		InitialDirContext context = new InitialDirContext(properties);
		try {
		Attributes userAttributes = AttributeFactory.createUserAttributes(user);
		context.createSubcontext("uid=" + user.getEmail() + DELIMITER + companyRDN, userAttributes);
		} finally {
			context.close();
		}
	}

	/**
	 * 公司注册步骤包括增加公司及第一个用户
	 * @param user
	 * @param connectionInfo
	 * @throws NamingException
	 */
	public static synchronized void registerCompany(User user, ConnectionInfo connectionInfo) throws NamingException {
		String dn = addCompany(user.getCompanyName(), connectionInfo);
		addUser(getRDN(dn), user);
	}
	

	/**
	 * 登录时验证用户名密码
	 * 
	 * @param dn
	 * @param user
	 * @throws NamingException
	 */
	public static synchronized boolean validateDN(String dn, String password) throws NamingException {
		InitialDirContext context = new InitialDirContext(properties);
		try {
			context.addToEnvironment(Context.SECURITY_PRINCIPAL, dn);
			context.addToEnvironment(Context.SECURITY_CREDENTIALS, password);
			context.lookup(getRDN(dn));
		} catch (NamingException e) {
			return false;
		} finally {
			context.addToEnvironment(Context.SECURITY_PRINCIPAL, properties.get("java.naming.security.principal"));
			context.addToEnvironment(Context.SECURITY_CREDENTIALS, properties.get("java.naming.security.credentials"));
			context.close();
		}
		return true;
	}

	/**
	 * 验证用户email是否已存在
	 * 
	 * @param dn
	 * @param user
	 * @throws NamingException
	 */
	public static synchronized boolean isEmailExist(String email) throws NamingException {
		InitialDirContext context = new InitialDirContext(properties);
		NamingEnumeration resultEnum = null;
		boolean isExist = false;
		try {
		String filter = "(&(objectClass=inetOrgPerson)(uid={0}))";
		SearchControls ctls = new SearchControls();
		ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		ctls.setReturningAttributes(new String[] { "" });
		resultEnum = context.search("", filter,
				new String[] { email }, ctls);
		isExist = resultEnum.hasMore();
		} finally {
			context.close();
		}
		return isExist;
	}

	/**
	 * 获取RDN
	 * 
	 * @param dn
	 * @return
	 */
	public static synchronized String getRDN(String dn) {
		return dn.substring(0, dn.lastIndexOf(DELIMITER));
	}

	/**
	 * 根据用户email获取用户DN
	 * 
	 * @param username
	 * @return
	 * @throws NamingException
	 */
	public static synchronized String getUserDN(String email) throws NamingException {
		String dn = null;
		String filter = "(&(objectClass=inetOrgPerson)(uid={0}))";

		SearchControls ctls = new SearchControls();
		ctls.setSearchScope(SearchControls.SUBTREE_SCOPE);
		ctls.setReturningAttributes(new String[]{""});
		
		InitialDirContext context = new InitialDirContext(properties);
		try {
			NamingEnumeration enm = context.search("", filter,
				new String[] { email }, ctls);
			if (enm.hasMore()) {
				SearchResult result = (SearchResult) enm.next();
				dn = result.getNameInNamespace();
			}
		} finally {
			context.close();
		}
		return dn;
	}

	/**
	 * 截取用户DN获取公司DN
	 * 
	 * @param userDN
	 * @return
	 */
	public static synchronized String getCompanyRDN(String userDN) {
		int rootDNindex = userDN.lastIndexOf(DELIMITER);
		String tempString = userDN.substring(0, rootDNindex);
		int companyDNindex = tempString.lastIndexOf(DELIMITER);
		String companyRDN = userDN.substring(companyDNindex + 1, rootDNindex);
		return companyRDN;
	}

	/**
	 * 根据公司DN获取连接信息
	 * 
	 * @param companyDN
	 * @return
	 * @throws NamingException
	 */
	public static synchronized ConnectionInfo getConnectionInfo(String companyRDN)
			throws NamingException {
		
		ConnectionInfo connectionInfo = null;
		String filter = "(&(objectClass=organization)({0}))";
		SearchControls ctls = new SearchControls();
		ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
		ctls.setReturningAttributes(new String[] { "javaReferenceAddress",
				"dbname", "dbusername", "dbpassword" });
		NamingEnumeration resultEnum = null;
		DirContext context = new InitialDirContext(properties);
		try {
			resultEnum = context.search("", filter,
				new String[] { companyRDN }, ctls);
			if (resultEnum.hasMore()) {
				SearchResult result = (SearchResult) resultEnum.next();
				Attributes attrs = result.getAttributes();
				Attribute dbNameAttribute = attrs.get("dbname");
				Attribute dbUsernameAttribute = attrs.get("dbusername");
				Attribute dbPassword = attrs.get("dbpassword");
				Attribute jndiURL = attrs.get("javaReferenceAddress");
				connectionInfo = new ConnectionInfo();
				connectionInfo.setDatabaseName((String) dbNameAttribute.get());
				connectionInfo.setPassword((String) dbPassword.get());
				connectionInfo.setUsername((String) dbUsernameAttribute.get());
				connectionInfo.setJndiURL((String) jndiURL.get());
			}
		} finally {
			context.close();
		}
		return connectionInfo;
	}

	public static synchronized boolean isCompanyExist(String companyName)
			throws NamingException {
		
		String filter = "(&(objectClass=organization)(o={0}))";
		SearchControls ctls = new SearchControls();
		ctls.setSearchScope(SearchControls.ONELEVEL_SCOPE);
		ctls.setReturningAttributes(new String[] { "" });
		NamingEnumeration resultEnum = null;
		DirContext context = new InitialDirContext(properties);
		boolean isExist = false;
		try {
			resultEnum = context.search("", filter,
				new String[] {companyName }, ctls);
			isExist = resultEnum.hasMore();
		} finally {
			context.close();
		}
		return isExist;
	}

	public static void resetPassword(String userDN, String password) throws NamingException {
		InitialDirContext context = new InitialDirContext(properties);
		Attributes attrs = new BasicAttributes();
		attrs.put("userPassword", Security.getApacheDSSHAEncoding(password));
		context.modifyAttributes(userDN, DirContext.REPLACE_ATTRIBUTE, attrs);
	}

}
